namespace VirtualCity.Initialization

open Casanova
open Casanova.Utilities
open Casanova.Core
open Casanova.Coroutines
open Casanova.Game
open Casanova.Input
open Casanova.Math
open Casanova.Drawing
open VirtualCity
open VirtualCity.World
open VirtualCity.City
open VirtualCity.Rendering
open Casanova.StandardLibrary.Core
open Casanova.StandardLibrary.Physics


/// Static class with a set of initializer methods for the 
/// various classes of the game. Some of the initializers
/// may be overloaded.
type Initialize() =

  /// Initialize the sprite layers.
  static member NewLayers(device,content,camera) =
    { 
      Background  = SpriteLayer.Create(device,content, BlendState.Opaque)
      Roads       = SpriteLayer.Create(device,content, BlendState.Opaque)
      Buildings   = SpriteLayer.Create(device,content)
      Items       = SpriteLayer.Create(device,content)
      Overlay     = SpriteLayer.Create(device,content)
      Agents      = SpriteLayer.Create(device,content)
      UI          = SpriteLayer.Create(device,content)
      Camera      = ref camera
    }


  /// Initialize the camera to a default position and with no
  /// freedom of movement.
  static member NewCamera(max_height) =  
    let bounds = 
      { 
        MinPosition       = Vector2.Zero
        MaxPosition       = Vector2.Zero
        MinHeight         = 2.0f<m>
        MaxHeight         = max_height
        NetworkingContext = NetworkingContext()
      }
    {
      Camera2D.Position = Rule.Create(Vector2.Zero)
      Velocity          = Rule.Create(Vector2.Zero)
      Height            = Rule.Create(5.0f<m>)
      Climb             = Rule.Create(0.0f<m/s>)
      Bounds            = var bounds
      NetworkingContext = NetworkingContext()
    }


  /// Setup the grid of background tiles for the city.
  static member NewTiles(layers,size) =
    let l,u = -size/2,size/2
    [
      for i = l to u do
        for j = l to u do
          yield DrawableSprite.Create(layers.Background, Vector2.Create(i, j) * 1000.0f / 10.0f,
                                      Vector2.Create(0.1f), 0.0f, Vector2.One * 0.5f, @"Tiles\DIRT", Color.White, true)
    ]


  static member NewDashboard(layers:Layers, automated_selection) =
    {
      SelectedAgent = Rule.Create None
      Box           = DrawableSprite.Create(layers.UI, Vector2.Create(-0.5f, -0.5f) * 1000.0f, Vector2.Create(0.15f,0.4f), 0.0f, Vector2.Zero, @"UI\WhitePixel", Color.White, true)
      ClockText     = DrawableText.Create(layers.UI, Vector2.Create(-0.49f, -0.45f) * 1000.0f, Vector2.One * 0.05f, Color.Black)
      AgentText     = DrawableText.Create(layers.UI, Vector2.Create(-0.49f, -0.35f) * 1000.0f, Vector2.Create(0.1f,0.3f), Color.Black)
      Selection     = DrawableSprite.Create(layers.Agents, Vector2.Zero, Vector2.Create(0.4f), @"UI\planet_selection_frame")
      Home          = DrawableSprite.Create(layers.Agents, Vector2.Zero, Vector2.Create(0.4f), @"UI\planet_selection_frame")
      Work          = DrawableSprite.Create(layers.Agents, Vector2.Zero, Vector2.Create(0.4f), @"UI\planet_selection_frame")
      AutoSelect    = automated_selection
      FPSCounter    = FPSCounter.Create(layers.UI, Vector2.Create(-0.49f, -0.5f) * 1000.0f, Vector2.One * 0.025f)
    }

  /// Create the initial world with a city that is generated from a
  /// "size x size" grid and with a certain set of buildings.
  static member NewWorld(device,content,size,buildings_distribution,max_height,automated_selection) =
    let camera = Initialize.NewCamera(max_height)
    let layers = Initialize.NewLayers(device,content,camera)
    let tiles  = Initialize.NewTiles(layers,size+4)
    let dashboard = Initialize.NewDashboard(layers, automated_selection)
    {
      City       = VirtualCity.Initialization.City.Initialize.NewCity(layers, size, buildings_distribution)
      Camera     = camera
      Layers     = layers
      Tiles      = tiles
      Dashboard  = dashboard
    }
  